package com.surekam.mnai.service.extractor;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import com.surekam.mnai.model.MobileNumberAttribution;
import com.surekam.mnai.service.extractor.parser.IMobileNumberAttributionParser;
import com.surekam.mnai.service.extractor.parser.ParseFailedException;

/**
 * 基于WebService的资源的抓取器。
 * 
 * @author 吴政
 * 
 */
public class WebServiceExtractor implements IMobileNumberAttributionExtractor {

	/**
	 * Http的请求调用方法。
	 */
	private String requestMethod;

	/**
	 * 请求参数中手机号码参数的名称。
	 */
	private String mobileNumberPropertyName;

	/**
	 * 使用限制记录器。
	 */
	private ILimitation limitation;

	/**
	 * URL构建者。
	 */
	private IHttpURLBuilder urlBuilder;

	/**
	 * 结果解析器。
	 */
	private IMobileNumberAttributionParser mobileNumberAttributionParser;

	/**
	 * 创建一个抓取器。
	 */
	public WebServiceExtractor() {
	}

	@Override
	public MobileNumberAttribution extract(String mobileNumber)
			throws OutOfLimitationException, ParseFailedException,
			ConnectionFailedException {
		checkLimit();

		setRequestProperty(mobileNumberPropertyName, mobileNumber);

		HttpURLConnection conn = getConnection();

		return parseMobileNumberAttribution(conn);
	}

	/**
	 * 检查使用限制。
	 * 
	 * @throws OutOfLimitationException
	 *             如果当前调用超出了使用限制，则抛出此异常。
	 */
	private void checkLimit() throws OutOfLimitationException {
		limitation.checkLimit();
	}

	/**
	 * 获取HTTP的URL连接。
	 * 
	 * @return URL连接
	 * @throws ConnectionFailedException
	 *             如果获取连接失败，则抛出此异常。
	 */
	private HttpURLConnection getConnection() throws ConnectionFailedException {
		try {
			URL url = getURL();
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			conn.setRequestMethod(requestMethod);
			//设置请求参数
			for (Map.Entry<String, String> e : urlBuilder
					.getRequestProperties().entrySet()) {
				conn.setRequestProperty(e.getKey(), e.getValue());
			}

			return conn;
		} catch (Exception e) {
			throw new ConnectionFailedException(e);
		}
	}

	/**
	 * 获取用于连接的URL对象。
	 * 
	 * @return URL对象
	 * @throws Exception
	 */
	private URL getURL() throws Exception {
		return urlBuilder.build();
	}

	/**
	 * 从指定的连接获取返回结果并解析为号码归属信息对象。
	 * 
	 * @param conn
	 *            连接
	 * @return 解析的号码归属信息对象
	 * @throws ParseFailedException
	 *             如果解析失败，则抛出此异常。
	 */
	private MobileNumberAttribution parseMobileNumberAttribution(
			HttpURLConnection conn) throws ParseFailedException {
		try {
			conn.connect();
			MobileNumberAttribution result = mobileNumberAttributionParser
					.parse(conn.getInputStream());
			conn.disconnect();

			return result;
		} catch (IOException e) {
			throw new ParseFailedException(e);
		}
	}

	/**
	 * 设置一般请求参数。
	 * 
	 * @param key
	 *            用于识别请求的关键字
	 * @param value
	 *            与该键关联的值
	 */
	public void setRequestProperty(String key, String value) {
		urlBuilder.setRequestProperty(key, value);
	}

	/**
	 * 移除请求参数。
	 * 
	 * @param key
	 *            用于识别请求的关键字
	 */
	public void removeRequestProperty(String key) {
		urlBuilder.removeRequestProperty(key);
	}

	/**
	 * 清空请求参数。
	 */
	public void clearRequestProperty() {
		urlBuilder.clearRequestProperty();
	}

	/**
	 * 获取指定的请求参数。
	 * 
	 * @param key
	 *            用于识别请求的关键字
	 * @return 与指定键关联的值
	 */
	public String getRequestProperty(String key) {
		return urlBuilder.getRequestProperty(key);
	}

	/**
	 * @return the endpoint
	 */
	public String getEndpoint() {
		return urlBuilder.getEndpoint();
	}

	/**
	 * @param endpoint
	 *            the endpoint to set
	 */
	public void setEndpoint(String endpoint) {
		urlBuilder.setEndpoint(endpoint);
	}

	/**
	 * @return the method
	 */
	public String getRequestMethod() {
		return requestMethod;
	}

	/**
	 * @param method
	 *            the method to set
	 */
	public void setRequestMethod(String requestMethod) {
		this.requestMethod = requestMethod;
	}

	public IMobileNumberAttributionParser getMobileNumberAttributionParser() {
		return mobileNumberAttributionParser;
	}

	public void setMobileNumberAttributionParser(
			IMobileNumberAttributionParser mobileNumberAttributionParser) {
		this.mobileNumberAttributionParser = mobileNumberAttributionParser;
	}

	public ILimitation getLimitation() {
		return limitation;
	}

	public void setLimitation(ILimitation limitation) {
		this.limitation = limitation;
	}

	public String getMobileNumberPropertyName() {
		return mobileNumberPropertyName;
	}

	public void setMobileNumberPropertyName(String mobileNumberPropertyName) {
		this.mobileNumberPropertyName = mobileNumberPropertyName;
	}

	public IHttpURLBuilder getUrlBuilder() {
		return urlBuilder;
	}

	public void setUrlBuilder(IHttpURLBuilder urlBuilder) {
		this.urlBuilder = urlBuilder;
	}

}
